package com.bbcare.followup.plat.service.impl;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;

import com.bbcare.comm.Constants;
import com.bbcare.comm.DateTimeUtil;
import com.bbcare.comm.SeqUtil;
import com.bbcare.followup.plat.service.IPatientMergeService;


/**
 * 广三患者随访数据合并。
 * @author michael
 */
@Service
public class PatientMergeService implements IPatientMergeService {
    private final static Logger logger = Logger.getLogger(PatientMergeService.class);

    private final static String QUERY_PATIENT   = "SELECT COUNT(*) FROM pt_queuescheme_info WHERE queue_id='%QUEUEID%' AND user_status='1' AND user_id='%USERID%'";
    private final static String QUERY_PTSCHEMEMID   = "SELECT pt_schemeid FROM pt_task_info WHERE queue_id='%QUEUEID%' AND user_id='%USERID%'";

    private final static String QUERY_TASK1 = "SELECT * FROM pt_task_info WHERE user_id='%USERID%' AND queue_id='%QUEUEID%' AND finish_date IS NOT NULL AND temporary_task IS NULL";
    private final static String QUERY_TASK3 = "SELECT * FROM pt_task_info WHERE user_id='%USERID%' AND queue_id='%QUEUEID%' AND finish_date IS NOT NULL AND temporary_task='1'";
    private final static String QUERY_TASK2 = "SELECT * FROM pt_task_info WHERE user_id='%USERID%' AND queue_id='%QUEUEID%' AND task_name='%TASKNAME%'";
    private final static String QUERY_TASK20= "SELECT COUNT(*) FROM pt_task_info WHERE user_id='%USERID%' AND queue_id='%QUEUEID%' AND task_name='%TASKNAME%'";
    private final static String UPDATE_TASK = "UPDATE pt_task_info SET finish_date='%FINISHDATE%', task_status='1' WHERE id='%ID%'";
    private final static String INSERT_TEMP_TASK=
            "INSERT INTO pt_task_info (id, user_id, pt_schemeid,task_name,  task_intro,  seq_no, execute_type,  window_day,  warn_day,  execute_day,  inform_flag,  author_id, update_time,   create_time,  execute_time,  task_status, begin_time,  end_time,  queue_id,     update_accept,  update_author,  next_address,  update_auname, task_type, next_task_id,  finish_time,  temporary_task, finish_date) " +
            "VALUES (                 :id,:user_id,:pt_schemeid, :task_name, :task_intro, :seq_no, :execute_type, :window_day, :warn_day, :execute_day, :inform_flag,:author_id, :update_time, :create_time, :execute_time, :task_status, :begin_time, :end_time, :queue_id, :update_accept, :update_author, :next_address, :update_auname, '0',       :next_task_id, :finish_time, :temporary_task, :finish_date)";

    private final static String QUERY_TASK_CONTENT  = "SELECT * FROM pt_taskcontent_info WHERE task_id='%TASKID%'";
    private final static String INSERT_TASK_CONTENT =
            "INSERT INTO pt_taskcontent_info (id,  task_id, templ_versionid,   update_time,  create_time, update_accept,  templ_type,  user_id,  pt_schemeid,  seq_no,  priority_no) " +
            "VALUES (                        :id, :task_id, :templ_versionid, :update_time, :create_time, :update_accept, :templ_type, :user_id, :pt_schemeid, :seq_no, :priority_no)";

    private final static String QUERY_CONTENT   = "SELECT * FROM pt_contentdata_info WHERE task_id='%'";
    private final static String INSERT_CONTENT  = "INSERT INTO pt_contentdata_info (id,user_id,task_id,question_id,question_answer,content_id,update_time,create_time,update_accept,pt_schemeid,templ_type,queue_id,tenant_id,source_type_create,source_type_update) VALUES (?,?,?,?,?,'',?,?,?,?,'0',?,?,'2','2');";
    private final static String DELETE_CONTENT  = "DELETE FROM pt_contentdata_info WHERE task_id='%TASKID%'";

    private final static String QUERY_GROWTH1   = "SELECT * FROM pt_growth_record WHERE user_id='%USERID%'";
    private final static String QUERY_GROWTH2   = "SELECT COUNT(*) FROM pt_growth_record WHERE user_id='%USERID%' AND test_time='%TESTTIME%' AND create_time='%CREATETIME%'";
    private final static String INSERT_GROWTH   =
            "INSERT INTO pt_growth_record (id, user_id,  height,  weight,  headcircumference, remark,  test_time,  create_time,  sourcetype,  actualresult,  result,  tenant_id,  doctorid )" +
            "VALUES (                    :id, :user_id, :height, :weight, :headcircumference, :remark, :test_time, :create_time, :sourcetype, :actualresult, :result, :tenant_id, :doctorid)";

    private final static Integer TEMPTASK_SEQNO = 999;  //临时随访的SeqNo。

    //查询重复建档患者的质疑列表。
    private final static Integer DUPED_PAGE_SIZE    = 10;   //已质疑列表缺省每页10行。
    private final static String QUERY_DUP_PAT_SQL   = "SELECT id,user_name,birthday,phone_no FROM pt_user_info WHERE tenant_id='%TENANTID%' AND id IN (SELECT user_id FROM pt_queuescheme_info WHERE queue_id='%QUEUEID%' AND user_status='1') ORDER BY birthday DESC";
    private final static Integer DUP_PAGE_SIZE      = 5;    //待质疑列表缺省每页5组。
    //插入质疑结果日志。
    private final static String INSERT_DUP_PAT_LOG  =
            "INSERT INTO pt_dup_pat_log (id,  tenant_id,  doctor_id, doctor_name,  from_id,   from_name, from_gender,   from_birthday,  from_phone,  to_id,  to_name, to_gender,  to_birthday,  to_phone,   queue_id, plan_task_result,   temp_task_result,  growup_result)" +
            "VALUES (                   :id, :tenant_id, :doctor_id, :doctor_name, :from_id, :from_name, :from_gender, :from_birthday, :from_phone, :to_id, :to_name, :to_gender, :to_birthday, :to_phone, :queue_id, :plan_task_result, :temp_task_result, :growup_result)";
    private final static String QUERY_PAT_INFO  = "SELECT * FROM pt_user_info WHERE id='%USERID%' AND tenant_id='%TENANTID%'";
    //查询质疑结果。
    private final static String QUERY_DUPED_LIST=
            "SELECT a.*,b.queue_name FROM pt_dup_pat_log a LEFT JOIN fu_queue_info b ON b.id=a.queue_id " +
            "WHERE a.tenant_id='%TENANTID%' AND a.queue_id='%QUEUEID%' ORDER BY a.insert_timestamp DESC LIMIT %START%,%END%";

    @Autowired
    private JdbcTemplate jdbc;
    @Autowired
    private NamedParameterJdbcTemplate namedJdbc;

    /**
     * 在targetMap中搜索birthday出生且name（或phone）相同的患者。
     * @param targetMap
     * @param birthday
     * @param name
     * @param phone
     */
    private List<Map<String,Object>> searchDup(final List<Map<String,Object>> targetMap,
                                               final String userId, final String birthday, final String name, final String phone, final String gender,
                                               final Integer groupIdx)  {
        String tBirthday,tName,tPhone,tId,tGender;
        Map<String,Object> dupPat;
        char order  = 'B';
        List<Map<String,Object>> dupList    = new ArrayList<>();
        for(Map<String,Object> patMap : targetMap)   {
            tId = patMap.get("id").toString();
            if (tId.equals(userId)) {
                //就是自己。
                continue;
            }
            tBirthday   = patMap.get("birthday").toString();
            tName   = patMap.get("user_name").toString();
            tPhone  = patMap.get("phone_no").toString();
            tGender = patMap.get("gender").toString();
            /*if (tBirthday.equals(birthday)) {
                if (tName.equals(name) || tPhone.equals(phone)) {
                    dupPat  = new HashMap<>();
                    dupPat.put("id",    tId);
                    dupPat.put("birthday",  tBirthday);
                    dupPat.put("user_name", tName);
                    dupPat.put("phone_no",  tPhone);
                    dupPat.put("group",     groupIdx);
                    dupPat.put("order",     Character.toString(order));
                    dupList.add(dupPat);
                    order++;
                }
            }*/

            /*
            if (tPhone.equals(phone) && tName.equals(name)) {
                //电话号码和姓名相同。
                dupPat  = new HashMap<>();
                dupPat.put("id",    tId);
                dupPat.put("birthday",  tBirthday);
                dupPat.put("user_name", tName);
                dupPat.put("phone_no",  tPhone);
                dupPat.put("group",     groupIdx);
                dupPat.put("order",     Character.toString(order));
                dupList.add(dupPat);
                order++;
            }

            if (tPhone.equals(phone) && tBirthday.equals(birthday)) {
                //电话号码和生日相同。
                dupPat  = new HashMap<>();
                dupPat.put("id",    tId);
                dupPat.put("birthday",  tBirthday);
                dupPat.put("user_name", tName);
                dupPat.put("phone_no",  tPhone);
                dupPat.put("group",     groupIdx);
                dupPat.put("order",     Character.toString(order));
                dupList.add(dupPat);
                order++;
            }
            */

            if (tPhone.equals(phone) && tBirthday.equals(birthday) && tGender.equals(gender) ) {
                //三项相同。
                dupPat  = new HashMap<>();
                dupPat.put("id",    tId);
                dupPat.put("birthday",  tBirthday);
                dupPat.put("user_name", tName);
                dupPat.put("phone_no",  tPhone);
                dupPat.put("gender",    tGender);
                dupPat.put("group",     groupIdx);
                dupPat.put("order",     Character.toString(order));
                dupList.add(dupPat);
                order++;
            }

        }
        return dupList;
    }

    /**
     * 查询待质疑列表。
     */
    public List<Map<String,Object>> queryDupPatList(final String tenantId, final String queueId, final Map<String,Object> paraMap)   {
        List<Map<String,Object>> allDupList = new ArrayList<>();
        Integer pageSize    = (Integer)paraMap.get("pageSize");
        if (null == pageSize)   {
            pageSize    = 1000;//DUP_PAGE_SIZE;
        }
        Integer pageNo  = (Integer)paraMap.get("pageNo");
        if (null == pageNo) {
            //缺省是第1页。
            pageNo  = 1;
        }

//        final String QUERY_SQL  = "SELECT id,user_name,birthday,phone_no FROM pt_user_info WHERE tenant_id='%TENANTID%' AND birthday>='2021-06-01' AND birthday<='2021-12-31' AND id IN (SELECT user_id FROM pt_queuescheme_info WHERE queue_id='%QUEUEID%' AND user_status='1') ORDER BY birthday DESC";
        final String QUERY_SQL  = "SELECT id,user_name,birthday,phone_no,gender FROM pt_user_info WHERE tenant_id='%TENANTID%' AND id IN (SELECT user_id FROM pt_queuescheme_info WHERE queue_id='%QUEUEID%' AND user_status='1') ORDER BY birthday DESC";
        //String sql  = QUERY_DUP_PAT_SQL.replaceAll("%TENANTID%", tenantId);
        String sql  = QUERY_SQL.replaceAll("%TENANTID%", tenantId);
        sql  = sql.replaceAll("%QUEUEID%", queueId);
        final List<Map<String,Object>> patList    = jdbc.queryForList(sql);
        List<Map<String,Object>> dupList;
        String userId, uBirthday,uName,uPhone,uGender;
        int curGroupIdx= 1;
        int addCnt  = 1;
        boolean found;
        final int startGroup  = (pageNo-1) * pageSize + 1;
        for(Map<String,Object> pat : patList)   {
            //pageNo需要处理。
            userId  = pat.get("id").toString();
            uBirthday   = pat.get("birthday").toString();
            uName   = pat.get("user_name").toString();
            uPhone  = pat.get("phone_no").toString();
            uGender = pat.get("gender").toString();
            found   = false;
            for(Map<String,Object> dupPat : allDupList)   {
                if (dupPat.get("id").toString().equals(userId)) {
                    found   = true;
                    break;
                }
            }
            if (found) {
                //userId的患者已经在allDupList中出现过了。
                continue;
            }
            dupList = searchDup(patList, userId, uBirthday, uName, uPhone, uGender, curGroupIdx);
            if (!dupList.isEmpty()) {
                if (curGroupIdx>=startGroup) {
                    pat.put("group", curGroupIdx);
                    pat.put("order", Character.toString('A'));
                    allDupList.add(pat);    //原始患者。
                    allDupList.addAll(dupList); //质疑患者列表。
                    addCnt += 1;
                }
                curGroupIdx += 1;
                if (addCnt > pageSize)   {
                    //1页已满，立即返回给前端。
                    break;
                }
            } else {
                //原始pat患者没有发生重复建档。
            }
        }

        return allDupList;
    }

    /**
     * 检查patId是否未被删除的高危儿队列患者。
     * @param patId
     * @return
     */
    private boolean checkUser(final String patId, final String queueuId)   {
        String sql  = QUERY_PATIENT.replaceAll("%USERID%", patId);
        sql = sql.replaceAll("%QUEUEID%", queueuId);
        Integer count  = jdbc.queryForObject(sql, Integer.class);
        if (1 == count.intValue())  {
            return true;
        }

        return false;
    }

    /**
     * 复制fromId的生长发育记录。
     * @param fromId
     * @param toId
     * @return 复制成功的记录数量。
     */
    private Map<String,Object> copyGrowthRecord(final String fromId, final String toId) {
        String sql1 = QUERY_GROWTH1.replaceAll("%USERID%",  fromId);
        final List<Map<String,Object>> fromGrowthList = jdbc.queryForList(sql1);
        String testTimeStr,createTimeStr,sql2,id;
        Integer count;
        int insRet,insTotal=0;
        Map<String,Object> paraMap;
        for(Map<String,Object> growthMap : fromGrowthList)   {
            testTimeStr     = growthMap.get("test_time").toString();
            createTimeStr   = growthMap.get("create_time").toString();
            sql2    = QUERY_GROWTH2.replaceAll("%TESTTIME%", testTimeStr);
            sql2    = sql2.replaceAll("%USERID%", toId);
            sql2    = sql2.replaceAll("%CREATETIME%", createTimeStr);
            count   = jdbc.queryForObject(sql2, Integer.class);
            if (0 == count) {
                //需要复制这条生长发育记录。
                id  = SeqUtil.getSeqNo();
                paraMap  = new HashMap<>();
                paraMap.put("id",   id);
                paraMap.put("user_id",  toId);
                paraMap.put("height",   growthMap.get("height"));
                paraMap.put("weight",   growthMap.get("weight"));
                paraMap.put("headcircumference",  growthMap.get("headcircumference"));
                paraMap.put("remark",   growthMap.get("remark"));
                paraMap.put("test_time",growthMap.get("test_time"));
                paraMap.put("create_time",growthMap.get("create_time"));
                paraMap.put("sourcetype",growthMap.get("sourcetype"));
                paraMap.put("actualresult",growthMap.get("actualresult"));
                paraMap.put("result",growthMap.get("result"));
                paraMap.put("tenant_id",growthMap.get("tenant_id"));
                paraMap.put("doctorid",growthMap.get("doctorid"));
                insRet  = this.namedJdbc.update(INSERT_GROWTH, paraMap);
                if (1 == insRet)    {
                    insTotal++;
                } else {
                    logger.error("----copyGrowthRecord() FAIL to insert pt_growth_record!");
                }
            } else {

            }
        }

        Map<String,Object> retMap   = new HashMap<>();
        retMap.put("msg", "FromId:"+fromId+"患者有"+fromGrowthList.size()+"条生长发育记录，已成功复制了"+insTotal+"条记录。");
        return retMap;
    }

    /**
     * 复制问卷答案。
     * @param contentMapList
     * @param fromPatId
     * @param toPatId
     * @param toTaskId
     * @return
     */
    private int copyContentList(final List<Map<String,Object>> contentMapList,
                                final String fromPatId, final String toPatId,
                                final String toTaskId,
                                final String toSchemeId)  {
        final int expectedSize  = contentMapList.size();
        logger.info("++++copyContent() there are "+expectedSize+" rows which is expected to copy from "+fromPatId+" to "+toPatId);
        int[] status = jdbc.batchUpdate(INSERT_CONTENT, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
                String questionId,questionAnswer,updateTime,createTime,updateAccept,queueId,tenantId;
                int fieldIdx= 1;
                updateTime  = contentMapList.get(i).get("update_time").toString();
                createTime  = contentMapList.get(i).get("create_time").toString();
                updateAccept= contentMapList.get(i).get("update_accept").toString();
                queueId     = contentMapList.get(i).get("queue_id").toString();
                tenantId    = contentMapList.get(i).get("tenant_id").toString();
                questionId      = contentMapList.get(i).get("question_id").toString();
                questionAnswer  = contentMapList.get(i).get("question_answer").toString();
                preparedStatement.setString(fieldIdx++, SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_PTTASK_CONTID));
                preparedStatement.setString(fieldIdx++, toPatId);
                preparedStatement.setString(fieldIdx++, toTaskId);
                preparedStatement.setString(fieldIdx++, questionId);
                preparedStatement.setString(fieldIdx++, questionAnswer);
                preparedStatement.setString(fieldIdx++, updateTime);
                preparedStatement.setString(fieldIdx++, createTime);
                preparedStatement.setString(fieldIdx++, updateAccept);
                preparedStatement.setString(fieldIdx++, toSchemeId);
                preparedStatement.setString(fieldIdx++, queueId);
                preparedStatement.setString(fieldIdx++, tenantId);
            }

            @Override
            public int getBatchSize() {
                return expectedSize;
            }
        });

        return status.length;
    }

    private int updateToTask(final String toTaskid, final String finishDate)  {
        String sql    = UPDATE_TASK.replaceAll("%FINISHDATE%", finishDate);
        sql    = sql.replaceAll("%ID%", toTaskid);
        int count = 0;
        try {
            count = jdbc.update(sql);
        } catch (DataAccessException dae)   {
            logger.error(dae);
        }

        return count;
    }

    private int deleteContent(final String taskId) {
        String sql    = DELETE_CONTENT.replaceAll("%TASKID%", taskId);
        int count = 0;
        try {
            count = jdbc.update(sql);
        } catch (DataAccessException dae)   {
            logger.error(dae);
        }

        return count;
    }

    /**
     * 复制pt_taskcontent_info.
     * @param fromTaskId
     * @param toTaskId
     */
    private int copyTempTaskContentInfo(final String fromId, final String toId,
                                        final String fromTaskId, final String toTaskId,
                                        final String fromSchemeId, final String toSchemeId)  {
        //query fromTaskContentInfo，有可能是多条记录。
        String sql  = QUERY_TASK_CONTENT.replaceAll("%TASKID%", fromTaskId);
        List<Map<String,Object>> fromTCIList    = jdbc.queryForList(sql);
        if (0 == fromTCIList.size()) {
            logger.error("----copyTaskContentInfo() do NOT find a task content info record for fromtaskid:"+fromTaskId);
            return 0;
        }

        //insert toTaskContentInfo.
        int insRet  = 0;
        Map<String, Object> paraMap = null;
        for(Map<String,Object> taskContentMap : fromTCIList) {
            paraMap = new HashMap<>();
            paraMap.put("id", SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_PTTASK_CONTID));
            paraMap.put("user_id",  toId);
            paraMap.put("task_id",  toTaskId);
            paraMap.put("seq_no",   TEMPTASK_SEQNO);
            paraMap.put("update_time",  taskContentMap.get("update_time"));
            paraMap.put("create_time",  taskContentMap.get("create_time"));
            paraMap.put("update_accept",taskContentMap.get("update_accept"));
            paraMap.put("templ_type",   taskContentMap.get("templ_type"));
            paraMap.put("pt_schemeid",  toSchemeId);
            paraMap.put("templ_versionid", taskContentMap.get("templ_versionid"));
            paraMap.put("priority_no",  0);
            insRet  = this.namedJdbc.update(INSERT_TASK_CONTENT, paraMap);
        }

        return insRet;
    }

    /**
     * 把需删除患者的所有临时随访任务复制给留存患者。
     * @param fromId 需删除患者的ID。
     * @param toId 留存患者的ID。
     */
    private Map<String,Object> copyTempTask(final String fromId, final String toId, final String queueId) {
        Map<String,Object> retMap   = new HashMap<>();
        String msg  = "";
        String sql  = QUERY_TASK3.replaceAll("%USERID%", fromId);
        sql = sql.replaceAll("%QUEUEID%", queueId);
        //查询需删除患者的临时随访任务。
        List<Map> taskList = null;
        try {
            taskList = jdbc.query(sql, new RowMapper<Map>() {
                public Map<String, String> mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map<String, String> row = new HashMap<String, String>();
                    row.put("taskId",   rs.getString("id"));
                    row.put("taskName", rs.getString("task_name"));
                    row.put("finishDate",   rs.getString("finish_date"));
                    row.put("pt_schemeid",  rs.getString("pt_schemeid"));
                    row.put("author_id",rs.getString("author_id"));
                    row.put("update_time",  rs.getString("update_time"));
                    row.put("create_time",  rs.getString("create_time"));
                    row.put("execute_time", rs.getString("execute_time"));
                    row.put("begin_time",   rs.getString("begin_time"));
                    row.put("end_time", rs.getString("end_time"));
                    row.put("queue_id", rs.getString("queue_id"));
                    row.put("update_accept",rs.getString("update_accept"));
                    row.put("update_author",rs.getString("update_author"));
                    row.put("next_address", rs.getString("next_address"));
                    row.put("update_auname",rs.getString("update_auname"));
                    row.put("update_author",rs.getString("update_author"));
                    row.put("finish_time",  rs.getString("finish_time"));
                    row.put("next_address", rs.getString("next_address"));
                    row.put("temporary_task", rs.getString("temporary_task"));
                    return row;
                }
            });
        } catch (DataAccessException dae)   {
            logger.error(dae);
            msg  = "查询需删除患者"+fromId+"的临时随访任务时发生异常，请查看日志文件！";
            retMap.put("msg",   msg);
            return retMap;
        }

        String toSchemeid   = "wrong";
        if (0 == taskList.size())   {
            msg  = "需删除患者" + fromId + "没有临时随访任务需要复制。";
            retMap.put("msg",msg);
            return retMap;
        } else {
            sql = QUERY_PTSCHEMEMID.replaceAll("%USERID%", toId);
            sql = sql.replaceAll("%QUEUEID%", queueId);
            List<Map<String,Object>> ptschemeidList    = jdbc.queryForList(sql);
            toSchemeid  = ptschemeidList.get(0).get("pt_schemeid").toString();
        }

        String fromTaskId,fromSchemeId,toTaskId,fromFinishDate,toFinishDate,tempTaskName;
        Map<String,Object> paraMap  = null;
        Integer count;
        int expectSize,insertSize, insTaskInfo,insTaskContentInfo;
        List<Map<String,Object>> contentMapList;
        StringBuffer sb = new StringBuffer();
        for(Map<String,String> fromTaskMap : taskList) {
            fromTaskId      = fromTaskMap.get("taskId");
            fromFinishDate  = fromTaskMap.get("finishDate");
            fromSchemeId    = fromTaskMap.get("pt_schemeid");
            toFinishDate    = fromFinishDate;
            toTaskId        = SeqUtil.getSeqNo(Constants.SEQ_NO_FOR_PTTASKID);
            tempTaskName    = fromTaskMap.get("taskName");
            sql = QUERY_TASK20.replaceAll("%USERID%", toId);
            sql = sql.replaceAll("%QUEUEID%", queueId);
            sql = sql.replaceAll("%TASKNAME%", tempTaskName);
            count   = jdbc.queryForObject(sql, Integer.class);
            if (0 != count.intValue())  {
                //toId已有同日期的临时随访，不能重复地复制相同日期的临时随访。
                continue;
            }

            paraMap  = new HashMap<>();
            paraMap.put("id",       toTaskId);
            paraMap.put("user_id",  toId);
            paraMap.put("task_name",tempTaskName);
            paraMap.put("pt_schemeid",  toSchemeid);
            paraMap.put("task_intro",   "临时随访");
            paraMap.put("execute_type", "1");
            paraMap.put("window_day",   0);
            paraMap.put("warn_day",     0);
            paraMap.put("execute_day",  0);
            paraMap.put("inform_flag",  "3");
            paraMap.put("task_status",  "1");
            paraMap.put("temporary_task","1");
            paraMap.put("author_id",    fromTaskMap.get("author_id"));
            paraMap.put("update_time",  fromTaskMap.get("update_time"));
            paraMap.put("create_time",  fromTaskMap.get("create_time"));
            paraMap.put("execute_time", fromTaskMap.get("execute_time"));
            paraMap.put("begin_time",   fromTaskMap.get("begin_time"));
            paraMap.put("end_time",     fromTaskMap.get("end_time"));
            paraMap.put("queue_id",     fromTaskMap.get("queue_id"));
            paraMap.put("update_accept",fromTaskMap.get("update_accept"));
            paraMap.put("update_author",fromTaskMap.get("update_author"));
            paraMap.put("next_address", fromTaskMap.get("next_address"));
            paraMap.put("update_auname",fromTaskMap.get("update_auname"));
            paraMap.put("finish_time",  fromTaskMap.get("finish_time"));
            paraMap.put("finish_date",  toFinishDate);
            paraMap.put("seq_no",       TEMPTASK_SEQNO);
            paraMap.put("next_task_id", "可以不填");
            try {
                //复制pt_task_info.
                insTaskInfo = this.namedJdbc.update(INSERT_TEMP_TASK, paraMap);
                //复制pt_taskcontent_info.
                insTaskContentInfo  = copyTempTaskContentInfo(fromId, toId, fromTaskId, toTaskId, fromSchemeId, toSchemeid);
                if (1 == insTaskInfo && 1 == insTaskContentInfo) {
                    //上面insert到pt_task_info和pt_taskcontent_info成功了。
                    sb.append("需留存患者宝宝").append(toId).append("成功增加了1个临时随访任务，任务名称：").append(tempTaskName).append("。");
                } else {
                    //insert失败，不需要insert pt_contentdata_info了。
                    sb.append("需留存患者宝宝").append(toId).append("未成功增加1个临时随访任务，任务名称：").append(tempTaskName).append("！");
                    continue;
                }

                //下面复制问卷答案。
                sql = QUERY_CONTENT.replaceAll("%", fromTaskId);
                contentMapList  = jdbc.queryForList(sql);    //原始问卷答案。
                expectSize  = contentMapList.size();
                insertSize  = copyContentList(contentMapList, fromId, toId, toTaskId, toSchemeid);  //batch insert.
                if (expectSize != insertSize)   {
                    sb.append("需留存患者宝宝").append(toId).append("的临时随访任务【").append(tempTaskName).append("】上增加了").append(insertSize).append("个问卷答案。");
                } else {
                    sb.append("需留存患者宝宝").append(toId).append("的临时随访任务【").append(tempTaskName).append("】上增加了").append(insertSize).append("个问卷答案。");
                }
            } catch (DataAccessException dae)   {
                logger.error(dae.getMessage());
                sb.append("需留存患者宝宝").append(toId).append("的临时随访任务【").append(tempTaskName).append("】复制问卷时发生异常，请查看日志文件！");
            }
        }

        msg = sb.toString();
        retMap.put("msg",  StringUtils.isBlank(msg)?"未复制任何的临时随访问卷。":msg);
        return retMap;
    }

    /**
     * 复制计划随访。
     * @param fromId
     * @param toId
     * @param queueId
     * @return
     */
    private Map<String,Object> copyPlannedTask(final String fromId, final String toId, final String queueId) {
        Map<String,Object> retMap   = new HashMap<>();
        String msg  = "";
        StringBuffer sb = new StringBuffer();
        String sql  = QUERY_TASK1.replaceAll("%USERID%", fromId);
        sql = sql.replaceAll("%QUEUEID%", queueId);
        //查询计划随访任务。
        List<Map> taskList = null;
        try {
            taskList = jdbc.query(sql, new RowMapper<Map>() {
                public Map<String, String> mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Map<String, String> row = new HashMap<String, String>();
                    row.put("taskId", rs.getString("id"));
                    row.put("taskName", rs.getString("task_name"));
                    row.put("finishDate", rs.getString("finish_date"));
                    return row;
                }
            });
        } catch (DataAccessException dae)   {
            logger.error(dae);
            msg  = "查询需删除患者"+fromId+"的计划随访任务时发生异常，请查看日志文件！";
            retMap.put("msg",   msg);
            return retMap;
        }
        if (0 == taskList.size())   {
            msg  = "需删除患者" + fromId + "没有已完成的计划随访任务需要复制。";
            retMap.put("msg",msg);
            return retMap;
        }

        Object finishDateObj;
        String fromTaskId,fromTaskName,toTaskName,toTaskId,fromFinishDate,toFinishDate,toSchemeId;
        int expectSize,insertSize,late;
        boolean copy;
        List<Map<String,Object>> contentMapList,toTaskList;
        for(Map<String,String> fromTaskMap : taskList)   {
            fromTaskId  = fromTaskMap.get("taskId");
            fromTaskName= fromTaskMap.get("taskName");
            toTaskName  = fromTaskName;
            fromFinishDate  = fromTaskMap.get("finishDate");
            sql = QUERY_CONTENT.replaceAll("%", fromTaskId);
            contentMapList  = jdbc.queryForList(sql);    //需要合并的计划随访的问卷答案。
            //目标患者的计划任务。
            copy= false;
            sql = QUERY_TASK2.replaceAll("%USERID%", toId);
            sql = sql.replaceAll("%QUEUEID%", queueId);
            sql = sql.replaceAll("%TASKNAME%", toTaskName);
            toTaskList   = jdbc.queryForList(sql);
            if (1 == toTaskList.size()) {
                toTaskId    = toTaskList.get(0).get("id").toString();
                toSchemeId  = toTaskList.get(0).get("pt_schemeid").toString();
                finishDateObj   = toTaskList.get(0).get("finish_date");
                toFinishDate    = null;
                if (null != finishDateObj && StringUtils.isNotBlank(finishDateObj.toString()))  {
                    //目标随访任务已完成了，比较源任务完成日期的早晚。
                    toFinishDate    = finishDateObj.toString();
                    late    = DateTimeUtil.compareDate(fromFinishDate, toFinishDate, 0);
                    if (1 == late)  {
                        //from的日期晚，需要合并。
                        copy    = true;
                    } else {
                        //不需要合并。
                        copy    = false;
                        logger.warn("----merge() toId:"+toId+", task:"+fromTaskName+", is finished on date "+toFinishDate+" is later than from task date "+fromFinishDate+", so we donot copy content.");
                    }
                } else {
                    //目标的计划随访任务未完成。
                    copy    = true;
                }

                if (copy)   {
                    if (StringUtils.isNotBlank(toFinishDate))   {
                        //需要删除旧的问卷答案。
                        deleteContent(toTaskId);
                    }

                    //开始合并（复制）。
                    try {
                        expectSize  = contentMapList.size();
                        insertSize  = copyContentList(contentMapList, fromId, toId, toTaskId, toSchemeId);  //batch insert.
                        if (expectSize != insertSize)   {
                            logger.warn("----merge() insertSize NOT equal to expectSize("+expectSize+"), copy "+insertSize+" content rows from patId:"+fromId+" to patId:"+toId);
                            sb.append("患者").append(toId).append("的计划随访任务【").append(toTaskName).append("】的问卷复制没有成功，仅复制了").append(insertSize).append("/").append(expectSize).append("个！");
                        } else {
                            logger.info("++++merge() insertSize equal to expectSize, succeed to copy "+insertSize+" content rows from patId:"+fromId+" to patId:"+toId);
                            sb.append("患者").append(toId).append("的计划随访任务【").append(toTaskName).append("】的问卷已复制成功了。");
                        }
                        //修改目标计划随访任务的finishDate。
                        if (0 != insertSize && 1 == updateToTask(toTaskId, fromFinishDate)) {
                            logger.info("++++merge() SUCCEED to update pt_task_info.");
                        } else {
                            logger.error("----merge() FAIL to update pt_task_info!");
                        }
                    } catch (DataAccessException dae)   {
                        logger.error(dae);
                    }
                }
            } else {
                logger.error("----merge() toId:"+toId+", do not exist a task for merge");
            }
        }

        msg = sb.toString();
        retMap.put("msg",  StringUtils.isBlank(msg)?"未复制任何的计划随访问卷。":msg);
        return retMap;
    }

    /**
     * 插入重复建档质疑操作结果日志。
     * @param parameters
     */
    private void insertMergeLog(final Map<String,Object> parameters)   {
        final String tenantId   = parameters.get("tenantId").toString();
        final String fromId = parameters.get("fromId").toString();
        final String toId   = parameters.get("toId").toString();
        String sql  = QUERY_PAT_INFO.replaceAll("%USERID%", fromId);
        sql = sql.replaceAll("%TENANTID%", tenantId);
        List<Map<String,Object>> resultList = jdbc.queryForList(sql);
        final String fromName   = resultList.get(0).get("user_name").toString();
        final String fromGender = resultList.get(0).get("gender").toString();
        final String fromPhone  = resultList.get(0).get("phone_no").toString();
        final String fromBirthday   = resultList.get(0).get("birthday").toString();

        sql = QUERY_PAT_INFO.replaceAll("%USERID%", toId);
        sql = sql.replaceAll("%TENANTID%", tenantId);
        resultList = jdbc.queryForList(sql);
        final String toName   = resultList.get(0).get("user_name").toString();
        final String toGender = resultList.get(0).get("gender").toString();
        final String toPhone  = resultList.get(0).get("phone_no").toString();
        final String toBirthday   = resultList.get(0).get("birthday").toString();

        final String id = SeqUtil.getSeqNo();
        Map<String,Object> paraMap  = new HashMap<>();
        paraMap.put("id",   id);
        paraMap.put("tenant_id",    tenantId);
        paraMap.put("doctor_id",    parameters.get("doctorId"));
        paraMap.put("doctor_name",  parameters.get("doctorName"));
        paraMap.put("queue_id", parameters.get("queueId"));
        paraMap.put("from_id",  fromId);
        paraMap.put("from_name",fromName);
        paraMap.put("from_gender",  fromGender);
        paraMap.put("from_phone",   fromPhone);
        paraMap.put("from_birthday",fromBirthday);
        paraMap.put("to_id",    toId);
        paraMap.put("to_name",  toName);
        paraMap.put("to_gender",toGender);
        paraMap.put("to_phone", toPhone);
        paraMap.put("to_birthday",toBirthday);
        paraMap.put("plan_task_result", parameters.get("planTaskResult"));
        paraMap.put("temp_task_result", parameters.get("tempTaskResult"));
        paraMap.put("growup_result",    parameters.get("growupResult"));
        int insRet  = this.namedJdbc.update(INSERT_DUP_PAT_LOG, paraMap);
        if (1 == insRet)    {
            logger.info("++++insertMergeLog() succeed to insert a merge log record.");
        } else {
            logger.info("----insertMergeLog() FAIL to insert a merge log record!");
        }
    }

    @Override
    public Map<String, Object> merge(final String tenantId, final String doctorId, final String doctorName, final String fromId, final String toId, final String queueId) throws Exception {
        Map<String,Object> retMap   = new HashMap<>();
        String msg;
        boolean existed = checkUser(fromId, queueId);
        if (!existed)   {
            msg = "队列"+queueId+"中不存在患者"+fromId;;
            retMap.put("msg", msg);
            return retMap;
        }
        existed = checkUser(toId, queueId);
        if (!existed)   {
            msg = "队列"+queueId+"中不存在患者"+toId;;
            retMap.put("msg", msg);
            return retMap;
        }

        //复制临时任务和问卷。
        Map<String,Object> tempRetMap   = copyTempTask(fromId, toId, queueId);
        //复制计划任务的问卷。
        Map<String,Object> plannedRetMap= copyPlannedTask(fromId, toId, queueId);
        final String planTaskResult = plannedRetMap.get("msg").toString();
        final String tempTaskResult = tempRetMap.get("msg").toString();
        retMap.put("临时随访复制结果：",  tempTaskResult);
        retMap.put("计划随访复制结果：",  planTaskResult);
        //复制pt_growth_record表中的对应记录。
        Map<String,Object> growthMap= copyGrowthRecord(fromId, toId);
        final String growupResult   = growthMap.get("msg").toString();
        retMap.put("生长发育复制结果：",  growupResult);

        Map<String,Object> logMap   = new HashMap<>();
        logMap.put("tenantId",  tenantId);
        logMap.put("doctorId",  doctorId);
        logMap.put("doctorName",doctorName);
        logMap.put("queueId",   queueId);
        logMap.put("fromId",    fromId);
        logMap.put("toId",      toId);
        logMap.put("planTaskResult",planTaskResult);
        logMap.put("tempTaskResult",tempTaskResult);
        logMap.put("growupResult",  growupResult);
        insertMergeLog(logMap);

        return retMap;
    }

    /**
     * 查询已质疑列表。
     * @param tenantId
     * @param queueId
     * @param paraMap
     * @return
     */
    public List<Map<String,Object>> queryDuplicatedList(final String tenantId, final String queueId, final Map<String,Object> paraMap) {
        Integer pageSize    = (Integer)paraMap.get("pageSize");
        if (null == pageSize || pageSize < 1)   {
            pageSize    = DUPED_PAGE_SIZE;
        }
        Integer pageNo  = (Integer)paraMap.get("pageNo");
        if (null == pageNo || pageNo < 1) {
            //缺省是第1页。
            pageNo  = 1;
        }
        int start   = (pageNo-1)*pageSize;
        int end = start + pageSize - 1;

        String sql  = QUERY_DUPED_LIST.replaceAll("%TENANTID%", tenantId);
        sql  = sql.replaceAll("%QUEUEID%", queueId);
        sql  = sql.replaceAll("%START%", Integer.valueOf(start).toString());
        sql  = sql.replaceAll("%END%", Integer.valueOf(end).toString());
        return jdbc.queryForList(sql);
    }
}
